package hj212

import (
	"net"
	"runtime/debug"
	"sync"

	"github.com/funny/link"
	"go.uber.org/zap"

	"gitee.com/whoiszhangben/hj212_recSvc/core/hj212/errors"
	"gitee.com/whoiszhangben/hj212_recSvc/core/hj212/protocol"
	"gitee.com/whoiszhangben/hj212_recSvc/global"
)

type Server struct {
	server          *link.Server
	mutex           sync.Mutex
	handler         sessionHandler
	sessions        map[uint64]*Session
	messageHandlers sync.Map
	closeHandler    func(session *Session)
	listenAddress   string
	protocol        link.Protocol
	sendChanSize    int
}

type Option struct {
	ListenAddress string
	SendChanSize  int
	Keepalive     int
	CloseHandler  func(session *Session)
	Protocol      link.Protocol
}

type MessageHandler func(session *Session, message *protocol.Message)

func NewServer(option Option) *Server {
	if option.Keepalive == 0 {
		option.Keepalive = 60
	}

	server := &Server{
		closeHandler:  option.CloseHandler,
		listenAddress: option.ListenAddress,
		sendChanSize:  option.SendChanSize,
		protocol:      option.Protocol,
		sessions:      make(map[uint64]*Session),
	}
	server.handler.server = server
	return server
}

func (server *Server) Run() error {
	if server.server != nil {
		return errors.ErrAlreadyRunning
	}
	if server.listenAddress == "" {
		server.listenAddress = "0.0.0.0:8192"
	}

	listener, err := net.Listen("tcp", server.listenAddress)
	if err != nil {
		global.GVA_LOG.Panic("server run error", zap.Any("err", err.Error()))
	}

	if server.protocol == nil {
		server.protocol = &Protocol{}
	}

	server.server = link.NewServer(listener, server.protocol, server.sendChanSize, server.handler)
	global.GVA_LOG.Info("protocol server started successfully", zap.String("address:", server.listenAddress))
	return server.server.Serve()
}

// GetSession 获取session
func (server *Server) GetSession(sessionID uint64) (*Session, bool) {
	server.mutex.Lock()
	defer server.mutex.Unlock()

	session, ok := server.sessions[sessionID]
	return session, ok
}

// AddHandler 添加消息处理器
func (server *Server) AddHandler(st uint16, handler MessageHandler) {
	if handler == nil {
		return
	}
	server.messageHandlers.Store(st, handler)
}

// RemoveHandler 移除消息处理器
func (server *Server) RemoveHandler(st, cn uint16) {
	server.messageHandlers.Delete(st + cn)
}

// Stop 停止服务
func (server *Server) Stop() {
	if server.server != nil {
		server.server.Stop()
		server.server = nil
	}
}

// dispatchMessage 分派消息
func (server *Server) dispatchMessage(session *Session, message *protocol.Message) {
	global.GVA_LOG.Debug("dispatch message", zap.String("deviceID", session.deviceID), zap.Uint16("st", message.Header.ST), zap.Uint16("cn", message.Header.CN))

	handler, ok := server.messageHandlers.Load(message.Header.CN)
	if !ok {
		global.GVA_LOG.Warn("dispatch message failed", zap.String("deviceID", session.deviceID), zap.Uint16("st", message.Header.ST), zap.Uint16("cn", message.Header.CN), zap.String("reason", "not found message handler"))
		return
	}

	handler.(MessageHandler)(session, message)
}

// handleClose 会话结束回调
func (server *Server) handleClose(session *Session) {
	server.mutex.Lock()
	delete(server.sessions, session.session.ID())
	server.mutex.Unlock()

	if server.closeHandler != nil {
		func() {
			if err := recover(); err != nil {
				debug.PrintStack()
			}
			server.closeHandler(session)
		}()
	}

	global.GVA_LOG.Warn("session closed", zap.String("deviceID", session.deviceID), zap.Uint64("sessionID", session.session.ID()))
}

func (server *Server) SessionCount() uint64 {
	return uint64(len(server.sessions))
}
